namespace Yaaf.Wp7.AdvancedExplorer.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Threading;

    using Yaaf.Wp7.AdvancedExplorer.Resources;
    using Yaaf.WP7.NativeAccess.Registry;

    public class RegistryViewModel : INotifyPropertyChanged, IPivotView
    {
        private readonly MainViewModel mainViewModel;

        private bool isWorking;

        public RegistryViewModel(MainViewModel mainViewModel)
        {
            this.mainViewModel = mainViewModel;
            RegistryEntries = new ObservableCollection<RegistryEntryViewModel>();
            currentRegistryKey = new RegistryKey("");
            currentRegistryKeyName = "/";
            mainViewModel.PropertyChanged += new PropertyChangedEventHandler(mainViewModel_PropertyChanged);
        }

        void mainViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "CurrentFilter" && mainViewModel.CurrentView == this)
            {
                this.RefreshRegistry();
            }
        }
        /// <summary>
        /// A collection for ItemViewModel objects.
        /// </summary>
        public ObservableCollection<RegistryEntryViewModel> RegistryEntries { get; private set; }

        public string CurrentRegistryKeyName
        {
            get
            {
                return this.currentRegistryKeyName;
            }

            private set
            {
                this.currentRegistryKeyName = value;
                this.NotifyPropertyChanged("CurrentRegistryKeyName");
            }
        }

        public WP7.NativeAccess.Registry.RegistryKey CurrentRegistryKey
        {
            get
            {
                return this.currentRegistryKey;
            }

            set
            {
                currentRegistryKey = value;
                CurrentRegistryKeyName = string.IsNullOrEmpty(currentRegistryKey.Name) ? "/" : currentRegistryKey.Name;

                try
                {
                    RefreshRegistry();
                }
                finally
                {
                    this.NotifyPropertyChanged("CurrentRegistryKey");
                }
            }
        }

        object workItem = new object();

        private void RefreshRegistry()
        {
            if (!Registry.IsAvailable)
            {
                RegistryEntries.Clear();
                RegistryEntries.Add(new RegistryEntryViewModel(new RegistryValue("\\" + AppResources.RegistryNotAvailable)));
                return;
            }

            if (isWorking)
            {
                stopWorking = true;
            }

            try
            {
                lock (workItem)
                {
                    if (isWorking)
                    {
                        throw new InvalidOperationException("Should not happen!");
                    }


                    isWorking = true;
                    RegistryEntries.Clear();
                    var filter = mainViewModel.CurrentFilter;
                    if (mainViewModel.IsFiltering && !string.IsNullOrEmpty(filter))
                    {
                        // Searching
                        ThreadPool.QueueUserWorkItem(state => SearchRegistry(CurrentRegistryKey, filter));
                    }
                    else
                    {
                        try
                        {
                            foreach (var subKey in this.CurrentRegistryKey.Keys)
                            {
                                RegistryEntries.Add(new RegistryEntryViewModel(subKey));
                            }
                            foreach (var valueName in this.CurrentRegistryKey.Values)
                            {
                                RegistryEntries.Add(new RegistryEntryViewModel(valueName));
                            }
                        }
                        finally
                        {
                            isWorking = false;
                        }
                    }
                }
            }
            catch (UnauthorizedAccessException e)
            {
                Logger.Instance.WriteLine("Ignoring UnauthorizedAccessException: {0}", e);
                // Ignore
            }
            finally
            {
                this.NotifyPropertyChanged("IsWorking");
            }
        }

        private void SearchRegistryPrivate(RegistryKey registryKey, string filter)
        {
            try
            {
                foreach (var valueName in registryKey.Values)
                {
                    if (valueName.Name.Contains(filter))
                    {
                        RegistryValue name = valueName;
                        mainViewModel.Invoke(() => RegistryEntries.Add(new RegistryEntryViewModel(name)));
                    }

                    if (stopWorking)
                    {
                        isWorking = false;
                        return;
                    }
                }
            }
            catch (UnauthorizedAccessException e)
            {
                Logger.Instance.WriteLine("Ignoring UnauthorizedAccessException: {0}", e);
                // Ignore
            }
            
            try
            {
                foreach (var subKey in registryKey.Keys)
                {
                    if (subKey.Name.Contains(filter))
                    {
                        RegistryKey key = subKey;
                        mainViewModel.Invoke(() => RegistryEntries.Add(new RegistryEntryViewModel(key)));
                    }

                    this.SearchRegistryPrivate(subKey, filter);

                    if (stopWorking)
                    {
                        isWorking = false;
                        return;
                    }
                }
            }
            catch (UnauthorizedAccessException e)
            {
                Logger.Instance.WriteLine("Ignoring UnauthorizedAccessException: {0}", e);
                // Ignore
            }
        }
        

        private void SearchRegistry(RegistryKey registryKey, string filter)
        {
            lock (workItem)
            {
                isWorking = true;
                try
                {
                    this.SearchRegistryPrivate(registryKey, filter);
                }
                finally
                {
                    IsWorking = false;
                }
            }
        }

        private string currentRegistryKeyName;

        private WP7.NativeAccess.Registry.RegistryKey currentRegistryKey;

        private bool stopWorking;

        public event PropertyChangedEventHandler PropertyChanged;

        public bool IsWorking
        {
            get
            {
                return isWorking;
            }
            set
            {
                isWorking = value;
                mainViewModel.Invoke(() => this.NotifyPropertyChanged("IsWorking"));
            }
        }

        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public void LoadData()
        {
            this.RefreshRegistry();
        }

        public string Header
        {
            get
            {
                return "registry";
            }
        }
    }
}